package com.zpself.module.算法练习.计算;

import com.google.common.collect.Lists;

import java.util.*;

/**
 * @author By ZengPeng
 * @Description 给你一个包含 n 个整数的数组 nums，判断 nums 中是否存在三个元素 a，b，c ，使得 a + b + c = 0 ？请你找出所有和为 0 且不重复的三元组。
 * 注意：答案中不可以包含重复的三元组。
 *
 * 示例 1：
 * 输入：nums = [-1,0,1,2,-1,-4]
 * 输出：[[-1,-1,2],[-1,0,1]]
 *
 * 示例 2：
 * 输入：nums = []
 * 输出：[]
 * @date in  2021/2/20 11:05
 * @Modified By
 */
public class 力扣_15_三数之和 {


    public static void main(String[] args) {
        System.out.println(threeSum(new int[]{-1,0,1,2,-1,-4}));
        System.out.println(threeSum(new int[]{-1,0,}));
    }

    public static List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> ans = new ArrayList<List<Integer>>();
        // 枚举 a
        for (int first = 0; first < n; ++first) {
            // 需要和上一次枚举的数不相同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c 对应的指针初始指向数组的最右端
            int third = n - 1;
            int target = -nums[first];
            // 枚举 b
            for (int second = first + 1; second < n; ++second) {
                // 需要和上一次枚举的数不相同
                if (second > first + 1 && nums[second] == nums[second - 1]) {
                    continue;
                }
                // 需要保证 b 的指针在 c 的指针的左侧
                while (second < third && nums[second] + nums[third] > target) {
                    --third;
                }
                // 如果指针重合，随着 b 后续的增加
                // 就不会有满足 a+b+c=0 并且 b<c 的 c 了，可以退出循环
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == target) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    ans.add(list);
                }
            }
        }
        return ans;
    }

    //题解：hash表 + 双重for循环  【超时】
    public static List<List<Integer>> threeSum2(int[] nums) {
        if(nums==null || nums.length<3)
            return new ArrayList<>();
        Arrays.sort(nums);
        //hash表 + 双重for循环
        ArrayList<List<Integer>> list = new ArrayList<>();
        for (int i = 0; i < nums.length; i++) {
            int num = nums[i];
            Map<Integer,int[]> map = new HashMap<>();//2等1
            for (int j = i+1; j < nums.length; j++) {
                int num1 = nums[j];
                if(map.containsKey(num1)){
                    int[] ints = map.get(num1);
                    List<Integer> data= new ArrayList<>();
                    data.add(ints[0]); data.add(ints[1]); data.add(num1);
                    if(list.contains(data))
                        continue;
                    list.add(data);
                }else {
                    map.put(0-(num+num1),new int[]{num,num1}) ;
                }
            }
        }
        return list;
    }
}
